use std::{collections::HashMap, sync::Arc, time::Instant};

use parking_lot::{Condvar, Mutex};

use crate::config;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};

lazy_static! {
    pub static ref SHARE_GLOBAL_AREA_MUTEX_PAIR: Arc<(
        parking_lot::lock_api::Mutex<parking_lot::RawMutex, GlobalAreaData>,
        Condvar
    )> = Arc::new((Mutex::new(GlobalAreaData::new()), Condvar::new()));
}

// pub fn get_lock() -> (parking_lot::lock_api::MutexGuard<'_, parking_lot::RawMutex, GlobalAreaData>, &parking_lot::Condvar) {

//     let &(ref lock, ref cvar) = &*SHARE_GLOBAL_AREA_MUTEX_PAIR.clone();
//     let mut loc = lock.lock();

//     (loc, cvar)
// }

pub const NON_LEADER: usize = 0;

#[derive(Debug, Clone)]
pub struct GlobalAreaData {
    // 投票数据
    pub vcd: VCData,
    // 状态：启动后默认
    pub status: Status,
    // 角色
    pub role: Role,
    // 集群内活跃的节点数
    pub attendees: HashMap<usize, usize>,
    // 离线的
    pub absents: HashMap<usize, usize>,
    // 暂存的票数
    pub scratch_poll: usize,
    pub scratch_poll_for: usize,
    // 支持者
    pub poll_from: Vec<VFrom>,
    // 投票失败
    pub poll_failed: Vec<VTo>,
    // 故障恢复后自动切换为leader
    auto_switchover: bool,
    // 权重: ServerID, weight
    server_weights: HashMap<usize, usize>,
    // max_weight: usize,
    enable_weight_future: bool,
    // 是否开放网关：只有leader选出后，才会开放网关
    // cgi = Common Gateway Interface
    cgi: bool,
    // 最小参与数量
    // quorum: usize,
    // 是否连接就绪
    pub connection_ready: HashMap<usize, bool>,
    
    // 执行重置的时间，重置后，需要等待一段时间，再进行投票，否则其他节点未重置
    pub reset_time: Instant,
    // 上一次的状态
    pub last_status: Status,
    pub last_role: Role,
    //
    // pub notify_files: HashMap<PathBuf, PayloadKind>,

    // pub notify_rm_files: HashMap<PathBuf, Option<String>>,
    // path: namespace
    // pub notify_path_ns_map: HashMap<PathBuf, String>,
}

#[derive(Debug, Clone)]
pub enum Status {
    Looking,
    // 在手上的票数投出，则会将状态改为Pending：
    // 状态流程为：Looking -> Pending -> Following
    // 该状态不接受投票，也不会投票给其他节点
    Pending,
    Following,
    Leading,
}

impl Status {
    #[allow(dead_code)]
    pub(crate) fn is_leading(&self) -> bool {
        match *self {
            Status::Leading => true,
            _ => false,
        }
    }

    #[allow(dead_code)]
    pub(crate) fn is_looking(&self) -> bool {
        match *self {
            Status::Looking => true,
            _ => false,
        }
    }

    #[allow(dead_code)]
    pub(crate) fn is_pending(&self) -> bool {
        match *self {
            Status::Pending => true,
            _ => false,
        }
    }

    #[allow(dead_code)]
    pub(crate) fn is_leading_or_following(&self) -> bool {
        match *self {
            Status::Leading | Status::Following => true,
            _ => false,
        }
    }
}

#[derive(Debug, Clone)]
pub enum Role {
    Follower,
    Leader,
    Singleton,
}

impl GlobalAreaData {
    pub fn new() -> Self {
        let vcd = VCData::new(1);
        let myid = vcd.myid;
        let mut attendees = HashMap::new();
        attendees.insert(myid, myid);
        let mut server_weights = HashMap::new();
        let mut connection_ready = HashMap::new();

        let mut max_weight = 0;
        let mut min_weight = config::get_members()[0].weight.unwrap_or_default();
        for node in config::get_members().iter() {
            let v = node.weight.unwrap_or_default();
            server_weights.insert(node.id, v);
            connection_ready.insert(node.id, false);
            if max_weight < v {
                max_weight = v;
            }
            if min_weight > v {
                min_weight = v;
            }
        }
        let enable_weight_future = !(min_weight == max_weight);
        log::trace!("enable_weight_future::{}", enable_weight_future);

        // let quorum = FastElectingRule::new().quorum();

        GlobalAreaData {
            vcd,
            status: Status::Looking,
            last_status: Status::Looking,
            role: Role::Follower,
            last_role: Role::Follower,
            attendees,
            scratch_poll: 0,
            scratch_poll_for: 0,
            poll_from: Vec::new(),
            poll_failed: Vec::new(),
            auto_switchover: false,
            server_weights,
            // max_weight,
            enable_weight_future,
            cgi: false,
            // quorum,
            absents: HashMap::new(),
            connection_ready,
            // notify_files: HashMap::new(),
            // notify_rm_files: HashMap::new(),
            // notify_path_ns_map: HashMap::new(),
            reset_time: Instant::now(),
        }
    }

    // 重置
    pub fn reset(&mut self) {
        self.vcd.reset(1);
        self.last_status = self.status.clone();
        self.status = Status::Looking;
        self.last_role = self.role.clone();
        self.role = Role::Follower;
        // 不允许清空，否则下一轮投票有问题
        // self.attendees.clear();
        // self.weight.clear();
        self.scratch_poll = 0;
        self.scratch_poll_for = 0;
        self.poll_from.clear();
        self.poll_failed.clear();
        self.auto_switchover = false;
        self.cgi = false;
        self.absents.clear();
        self.reset_time = Instant::now();
        // self.notify_files.clear();
    }

    // 是否可以自动切换为leader
    pub fn is_auto_switchover(&self) -> bool {
        if !config::get_server_auto_switchover() {
            return false;
        }
        // log::debug!("weight = {:?}", self.weight);
        // log::debug!("attendees = {:?}", self.attendees);
        // 票数过半
        // let is_valid_quorum = self.attendees.len() >= self.quorum;
        // 最大的权重才有权限
        // 1、是否我是权重最大的
        // 场景A： 1 1 1，无需自动切换
        // 场景B： 1 2 2，leader节点权重为1时，本节点为2，需要自动切换
        // 场景C： 1 2 3，leader节点权重为2时，本节点为3，需要自动切换
        // let is_valid_weight =
        //     self.weight.len() >= self.quorum && self.max_weight == self.vcd.weight;
        // 2、且我当前不是leader
        // let is_valid = is_valid_quorum & is_valid_weight & !self.vcd.is_leader();

        // leader weight
        let leader_weight = match config::get_node_byid(self.vcd.leader) {
            Some(node) => node.weight.unwrap_or_default(),
            None => 0,
        };
        // 场景B & C
        let is_valid_weight_cond = leader_weight < self.vcd.weight;

        self.auto_switchover & self.enable_weight_future & self.has_leader() & is_valid_weight_cond
    }

    // 开启自动切换功能
    pub fn enable_auto_switchover(&mut self) {
        self.auto_switchover = true;
    }

    // 关闭自动切换功能
    pub fn disable_auto_switchover(&mut self) {
        self.auto_switchover = false;
    }

    // 此时leader是否在线
    pub fn is_leader_online(&mut self) -> bool {
        log::trace!("leader: {}", self.vcd.leader);
        log::trace!("attendees: {:?}", self.attendees.keys());
        self.attendees.contains_key(&self.vcd.leader)
    }

    #[allow(dead_code)]
    pub fn is_leader_offline(&mut self) -> bool {
        !self.is_leader_online()
    }

    // 计算最大权重
    // 离线的节点不应该被计算进来
    pub fn get_max_weight(&self) -> usize {
        log::trace!("weight = {:?}", self.server_weights);
        log::trace!("attendees = {:?}", self.attendees);

        let mut max_weight = 0;
        // 在线节点
        for id in self.attendees.keys() {
            // 通过在线节点获取权重
            let w = match self.server_weights.get(id) {
                Some(w) => w.to_owned(),
                None => 0,
            };
            if max_weight < w {
                max_weight = w;
            }
        }
        max_weight
    }

    // 投票成功
    pub fn poll(&mut self, vcd: &VCData) {
        self.vcd.poll += vcd.poll;
        let vf = VFrom::new(vcd.myid, vcd.poll);
        if !self.is_poll_from(&vf.id) {
            self.poll_from.push(vf.clone());
        }
    }

    // 投票是否来源指定ID
    pub fn is_poll_from(&self, id: &usize) -> bool {
        for v in self.poll_from.iter() {
            if v.id == id.to_owned() {
                if !self.status.is_leading_or_following() {
                    log::info!("Poll [{}] from {id}", v.p);
                }
                return true;
            }
        }
        false
    }

    // 是否已经有一次投票失败
    pub fn is_poll_failed(&self, id: &usize) -> bool {
        for v in self.poll_failed.iter() {
            if v.id == id.to_owned() {
                if !self.status.is_leading_or_following() {
                    log::info!("Voting to {id}, failed");
                }
                return true;
            }
        }
        false
    }

    // 是否已经投票给指定ID
    pub fn is_poll_to(&self, id: &usize) -> bool {
        if let Some(v) = &self.vcd.poll_to {
            if v.id == id.to_owned() {
                if !self.status.is_leading_or_following() {
                    log::info!("Poll [{}] to {id}", v.p);
                }
                return true;
            }
        }
        false
    }

    // 是否已经投票过
    // pub fn is_voted(&self, id: &usize) -> bool {
    //     self.is_poll_from(id) | self.is_poll_failed(id) | self.is_poll_to(id)
    // }

    #[allow(dead_code)]
    pub fn get_vcd(&self) -> VCData {
        return self.vcd.clone();
    }

    // 投票失败
    pub fn voting_failed(&mut self, id: usize, p: usize) {
        self.poll_failed.push(VTo { id, p });
    }

    // 同步leader信息
    pub fn sync_leader(&mut self, leader: usize, term: usize, status: Status) {
        self.vcd.sync_leader(leader, term);
        self.status = status;
        self.role = match self.status {
            Status::Leading => Role::Leader,
            _ => Role::Follower,
        };
    }

    // 判断ID是否为leader
    pub fn is_leader(&self, id: usize) -> bool {
        self.vcd.leader == id
    }

    // 当前环境是否有leader
    pub fn has_leader(&self) -> bool {
        self.status.is_leading_or_following()
    }

    // 当前环境是否有leader
    pub fn is_leading(&self) -> bool {
        self.status.is_leading()
    }

    // 当前状态是否pending，票投出后会从Looking->Pending
    pub fn is_pending(&self) -> bool {
        self.status.is_pending()
    }

    // 是否存在暂存投票
    pub fn has_scratch_poll(&self) -> bool {
        self.scratch_poll > 0
    }

    // 暂存投票
    pub fn scratch_for(&mut self, for_id: usize) {
        if self.vcd.poll == 0 {
            return;
        }

        log::trace!(
            "scratch_poll_for:{}, scratch_poll:{}",
            for_id,
            self.vcd.poll
        );
        self.scratch_poll = self.vcd.poll;
        self.scratch_poll_for = for_id;
        self.vcd.poll = 0;
    }

    // 清理暂存投票
    pub fn clean_scratch(&mut self) {
        self.scratch_poll = 0;
        self.scratch_poll_for = 0;
    }

    // 从暂存投票取回
    pub fn retrieve(&mut self) {
        if self.scratch_poll == 0 {
            return;
        }

        log::trace!(
            "retrieve==> scratch_poll:{}, scratch_poll_for:{}",
            self.scratch_poll,
            self.scratch_poll_for
        );

        self.vcd.poll += self.scratch_poll;
        self.scratch_poll = 0;
        self.scratch_poll_for = 0;
    }

    // 更新投票去向
    pub fn poll_to_with_scratch(&mut self, id: usize) {
        self.vcd.poll_to = Some(VTo::new(id, self.scratch_poll));
    }

    // 更新在线节点数
    pub fn online(&mut self, id: usize) {
        // 保存
        if let None = self.attendees.insert(id, id) {
            self.absents.remove(&id);
        }
        self.connection_ready.insert(id, true);
    }

    // 更新在线节点数
    pub fn offline(&mut self, id: usize) {
        if let Some(k) = self.attendees.remove(&id) {
            // 告知其他线程
            self.absents.insert(k, k);
        }
        self.connection_ready.insert(id, false);
    }

    #[allow(dead_code)]
    pub fn fmt(&self) -> String {
        format!(
            "{{ status = \"{:?}\", vcd = {} }}",
            self.status,
            serde_json::to_string(&self.vcd).unwrap()
        )
    }
}

// 基本信息
// Vote Core Data
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct VCData {
    // 数据唯一性标识
    // trace_id: u16,
    // leader ID
    pub leader: usize,
    pub myid: usize,
    // 任期数
    pub term: usize,
    // 投票数
    pub poll: usize,
    // 事务次数，每同步一次数据后 +1
    pub tranx: usize,
    // 权重
    pub weight: usize,
    // 票数去向
    pub poll_to: Option<VTo>,
}

impl VCData {
    pub fn new(poll: usize) -> Self {
        // use rand::Rng;
        VCData {
            // trace_id: rand::thread_rng().gen::<u16>(),
            leader: NON_LEADER,
            myid: config::get_server_id(),
            term: 0,
            poll,
            tranx: 0,
            weight: config::get_my_weight(),
            poll_to: None,
        }
    }

    // 我是否为leader
    #[allow(dead_code)]
    pub fn is_leader(&self) -> bool {
        self.leader == self.myid
    }

    // 重置
    pub fn reset(&mut self, poll: usize) {
        self.leader = NON_LEADER;
        self.poll = poll;
        self.poll_to = None;
    }

    // 同步leader信息
    pub fn sync_leader(&mut self, leader: usize, term: usize) {
        self.leader = leader;
        // 同步投票周期
        self.term = term;
    }

    // 同步数据
    pub fn sync_with(&mut self, vcd: &VCData) {
        self.leader = vcd.leader;
        self.term = vcd.term;
        self.tranx = vcd.tranx;
    }

    // 票已投出
    pub fn pollout(&mut self, id: usize, p: usize) {
        self.poll_to = Some(VTo::new(id, p));
        self.poll = 0;
    }

    pub fn fmt(&self) -> String {
        serde_json::to_string(&self).unwrap()
    }
}

// Vote From
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct VFrom {
    // 投票来源 id
    pub id: usize,
    // 投出票数
    pub p: usize,
}

impl VFrom {
    pub fn new(id: usize, p: usize) -> Self {
        VFrom { id, p }
    }
}

// Vote To
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct VTo {
    // 投票去向 id
    pub id: usize,
    // 投出票数
    pub p: usize,
}

impl VTo {
    pub fn new(id: usize, p: usize) -> Self {
        VTo { id, p }
    }
}
